package com.gaodun.hk.infrastructure.swagger;

import cn.hutool.core.util.StrUtil;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author fengyamin
 * @date 2020/04/14
 **/
@Configuration
@EnableSwagger2
@Profile({"!production"})
@EnableConfigurationProperties({SwaggerProperties.class})
public class SwaggerConfig {
    private final static String SWAGGER_UI_HEADER = "Referer";

    @Bean
    public Docket api(SwaggerProperties swaggerProperties) {
        return (new Docket(DocumentationType.SWAGGER_2))
                .apiInfo(apiInfo(swaggerProperties))
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .apis(RequestHandlerSelectors.any())
                .build()
                .enable(swaggerProperties.getEnabled())
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
        return (new ApiInfoBuilder())
                .title(StrUtil.isNotEmpty(swaggerProperties.getTitle()) ? swaggerProperties.getTitle() : "开放接口API")
                .description(StrUtil.isNotEmpty(swaggerProperties.getDescription()) ? swaggerProperties.getDescription() : "HTTP对外开放接口")
                .version(StrUtil.isNotEmpty(swaggerProperties.getVersion()) ? swaggerProperties.getVersion() : "1.0.0")
                .termsOfServiceUrl(StrUtil.isNotEmpty(swaggerProperties.getTermsOfServiceUrl()) ? swaggerProperties.getTermsOfServiceUrl() : "https://gaodun.com")
                .license(StrUtil.isNotEmpty(swaggerProperties.getLicense()) ? swaggerProperties.getLicense() : "LICENSE")
                .licenseUrl(StrUtil.isNotEmpty(swaggerProperties.getLicenseUrl()) ? swaggerProperties.getLicenseUrl() : "https://gaodun.com")
                .contact(new Contact(
                        StrUtil.isNotEmpty(swaggerProperties.getContactName()) ? swaggerProperties.getContactName() : "架构组",
                        StrUtil.isNotEmpty(swaggerProperties.getContactUrl()) ? swaggerProperties.getContactUrl() : "",
                        StrUtil.isNotEmpty(swaggerProperties.getContactEmail()) ? swaggerProperties.getContactEmail() : "")
                )
                .build();
    }

    /**
     * 安全验证模式
     *
     * @return {@code List<ApiKey>} 列表
     */
    private List<ApiKey> securitySchemes() {
        List<ApiKey> apiKeyList = new ArrayList<>();
        apiKeyList.add(new ApiKey("C端", "X-GATEWAY-SID", "header"));
        apiKeyList.add(new ApiKey("B端", "X-GATEWAY-UID", "header"));
        return apiKeyList;
    }

    /**
     * 安全上下文
     *
     * @return {@code List<SecurityContext>} 列表
     */
    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .build());
        return securityContexts;
    }

    /**
     * 安全关联设置
     *
     * @return {@code List<SecurityReference>} 列表
     */
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("C端", authorizationScopes));
        securityReferences.add(new SecurityReference("B端", authorizationScopes));
        return securityReferences;
    }

    @Bean
    public OncePerRequestFilter swaggerCorsFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(
                    @NonNull HttpServletRequest request,
                    @NonNull HttpServletResponse response,
                    @NonNull FilterChain filterChain) throws ServletException, IOException {
                if (request.getHeader(SWAGGER_UI_HEADER) != null) {
                    response.addHeader(
                            "Access-Control-Allow-Origin",
                            request.getHeader("origin")
                    );
                    response.addHeader(
                            "Access-Control-Allow-Headers",
                            "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With," +
                                    "If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range," +
                                    "Authorization,X-GATEWAY-UID,X-GATEWAY-SID"
                    );
                    response.addHeader(
                            "Access-Control-Allow-Methods",
                            "GET, POST, PUT, DELETE, PATCH, OPTIONS"
                    );
                }
                filterChain.doFilter(request, response);
            }
        };
    }
}
